#include <kutils.h>
#include "display.h"
#include "pci.h"
#include "hardware_detection.h"

u8int pci_read_config_u8int(u16int bus, u16int slot, u16int func, u16int reg);
u16int pci_read_config_u16int(u16int bus, u16int slot, u16int func, u16int reg);
u32int pci_read_config_u32int(u16int bus, u16int slot, u16int func, u16int reg);

void pci_scan()
{
#ifdef FLUIDIUM_DEBUG
	write_string("PCI: Begin scan...\n\n");
#endif

	u16int bus = 0;
	u16int slot = 0;
	u16int vendor = 0;
	u16int device = 0;

	for(bus = 0; bus < 4; bus++)
	{
		for(slot = 0; slot < 16; slot++)
		{
			vendor = pci_read_config_u16int(bus, slot, 0, PCI_VENDOR);
			device = pci_read_config_u16int(bus, slot, 0, PCI_DEVICE);
			if(vendor != 0xFFFF)
			if(device != 0xFFFF)
			{
				u8int class 	= pci_read_config_u8int(bus, slot, 0, PCI_CLASS);
				u8int subclass = pci_read_config_u8int(bus, slot, 0, PCI_SUBCLASS);
				u8int prog_if 	= pci_read_config_u8int(bus, slot, 0, PCI_PROGIF);
				u8int revision = pci_read_config_u8int(bus, slot, 0, PCI_REVISION);

				hw_add_device(HW_BUS_TYPE_PCI, device, vendor, class, subclass, prog_if, revision, 0, 0);
			}
		}
	}

#ifdef FLUIDIUM_DEBUG
	write_string("PCI: Scan complete.\n");
#endif
}

u8int pci_read_config_u8int(u16int bus, u16int slot, u16int func, u16int reg)
{
	return (u8int)( (pci_read_config_u32int(bus, slot, func, reg) >> (8 * (reg & 0x03) ) ) & 0x000000FF );
}

u16int pci_read_config_u16int(u16int bus, u16int slot, u16int func, u16int reg)
{
	return (u16int)( (pci_read_config_u32int(bus, slot, func, reg) >> (8 * (reg & 0x02) ) ) & 0x0000FFFF );
}

u32int pci_read_config_u32int(u16int bus, u16int slot, u16int func, u16int reg)
{
   u32int address;
   u32int lbus = (u32int)bus;
   u32int lslot = (u32int)slot;
   u32int lfunc = (u32int)func;
 
   address = (u32int)((lbus << 16) | (lslot << 11) | (lfunc << 8) | (reg & 0xfc) | ((u32int)0x80000000));
 
   outportl(PCI_CONFIG_ADDRESS, address);
   return inportl(PCI_CONFIG_DATA);
}

